#pragma once
// 把之前写的命名管道封装起来进行管理（描述起来）
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <unistd.h>
#include <fcntl.h>
#include"Comm.hpp"
#define PATH "."
#define FILENAME "fifo"
// 作用是如果错误的话，打印错误信息，并返回相应的退出码
#define ERR_EXIT(m)         \
    do                      \
    {                       \
        perror(m);          \
        exit(EXIT_FAILURE); \
    } while (0)

// 命名管道的创建（封装一下）
class NameFifo
{
    // 构造函数的时候就可以把管道文件创建好
public:
    NameFifo(const std ::string &path, const std ::string &name)
        : _path(path),
          _name(name)
    {
        // 创造一个管道文件
        _fifoname = _path + "/" + _name;         // 此时一个完整的pathname就成功的创建了
        int n = mkfifo(_fifoname.c_str(), 0666); // 在当前文件创造一个（命名）管道文件
        if (n < 0)
        {
            std ::cout << "mkfifo failed" << std ::endl;
        }
        else
        {
            std ::cout << "mkfifo success" << std ::endl;
        }
    }
    ~NameFifo()
    {
        int n = unlink(_fifoname.c_str()); // 这个函数可以用来删除系统下的文件，给定一个绝对路径就可以。
        if (n == 0)
        {
            ERR_EXIT("unlink");  //代表着成功删除
        }
        else
        {
            std ::cout << "remove fifo failed" << std ::endl;
        }
    }

private:
    std ::string _path;     // 创建时的路径
    std ::string _name;     // 创建时管道的名字
    std ::string _fifoname; // 在使用mkfifo时完整的管道名字（pathname）
};

// 使用者开始
class FileOper
{
public:
    FileOper(const std ::string &path, const std ::string &name)
        : _path(path),
          _name(name)
    {
        // 记录一下当前的管道文件到底是在哪里
        _fifoname = _path + "/" + _name;
    }
    // 打开文件分为两种方式：打开为了写，打开为了读
    void OpenforRead()
    {
        // 打开的方式是读取
        _fd = open(_fifoname.c_str(), O_RDONLY);
        if (_fd < 0)
            ERR_EXIT("open");
        std ::cout << "open fifo success" << std ::endl;
    }
    void OpenforWrite()
    {
        // 打开的方式是写入
        _fd = open(_fifoname.c_str(), O_WRONLY);
        if (_fd < 0)
            ERR_EXIT("open");
        std ::cout << "open fifo success" << std ::endl;
    }
    // 写端
    void Writer()
    {
        // 执行写入操作
        std ::string message;
        int cnt = 1;
        pid_t id = getpid();
        while (true)
        {
            std ::cout << "Please Enter# ";
            std ::getline(std ::cin, message);
            message += (", message number: " + std::to_string(cnt++) + ", [" + std::to_string(id) + "]");
            write(_fd, message.c_str(), message.size()); // 此时已经把内容写到管道文件了  //直接调用容器接口就好了
        }
    }
    // 读端
    void Reader()
    {
        // 通过循环的方式去读
        while (true)
        {
            char buffer[1024];
            int number = read(_fd, buffer, sizeof(buffer) - 1);
            if (number > 0)
            {
                buffer[number] = 0;
                std ::cout << "Client say#  " << buffer << std ::endl;
            }
            else if (number == 0) // 此时什么数据也没有读到，说明写关闭了，但是读继续了
            {
                std ::cout << "client quit! me too!" << std ::endl;
                break;
            }
            else
            {
                std ::cerr << "read error" << std ::endl;
                break;
            }
        }
    }
    void Close()
    {
        if(_fd > 0)
        close(_fd);
    }

    bool Wait()
    {
        char c;
        int number = read(_fd,&c,1);  //read函数返回的是成功读取的字节数
        if(number > 0)
        {
            printf("唤醒成功！:%d\n",number);
            return true;
        }
        return false;
    }


    void  wakeup()
    {
        char c = 'c';
        int number = write(_fd,&c,1);
        printf("尝试唤醒：%d\n",number);
    }
    ~FileOper()
    {

    }

private:
    std ::string _path;     // 创建时的路径
    std ::string _name;     // 创建时管道的名字
    std ::string _fifoname; // 在使用mkfifo时完整的管道名字（pathname）
    int _fd;                // 记录文件描述符
};